﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using System.Collections;
using System.Xml.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.IO;

namespace Quix
{
    public static class Core
    {
        private static string _FarmRootUrl = "";

        public static string GetFarmRootUrl()
        {
            if (_FarmRootUrl == "")
            {
                Microsoft.SharePoint.Administration.SPFarm farm = Microsoft.SharePoint.Administration.SPFarm.Local;
                if (farm != null)
                {
                    foreach (Microsoft.SharePoint.Administration.SPAlternateUrlCollection alternateurlcollection in farm.AlternateUrlCollections)
                    {
                        if (_FarmRootUrl == "")
                        {
                            foreach (Microsoft.SharePoint.Administration.SPAlternateUrl alternateurl in alternateurlcollection)
                            {
                                if (alternateurl.UrlZone == Microsoft.SharePoint.Administration.SPUrlZone.Default)
                                {
                                    if (alternateurl.Uri.Port == 80)
                                    {
                                        _FarmRootUrl = alternateurl.Uri.AbsoluteUri;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return _FarmRootUrl;
        }

        /// <summary>
        /// Write to screen as well as log file.
        /// </summary>
        /// <param name="str">Text to write.</param>
        /// <param name="sw">Log file stream to write to.</param>
        public static void Log(string str, System.IO.StreamWriter sw)
        {
            Console.WriteLine(DateTime.Now.ToString() + " => " + str);
            sw.WriteLine(DateTime.Now.ToString() + " => " + str);
            sw.Flush();
        }

        /// <summary>
        /// Write to screen as well as log file in a given color, saving and restoring the original screen text color when complete.
        /// </summary>
        /// <param name="str">Text to write.</param>
        /// <param name="sw">Log file stream to write to.</param>
        /// <param name="col">Console color to use when writing text.</param>
        public static void Log(string str, System.IO.StreamWriter sw, ConsoleColor col)
        {
            ConsoleColor clr = Console.ForegroundColor;
            Console.ForegroundColor = col;
            Console.WriteLine(DateTime.Now.ToString() + " => " + str);
            Console.ForegroundColor = clr;
            sw.WriteLine(DateTime.Now.ToString() + " => " + str);
            sw.Flush();
        }

        /// <summary>
        /// Generate a log file name from the executable name plus a given command argument.
        /// </summary>
        /// <param name="str">The command argument string to use.</param>
        /// <returns>New log file name.</returns>
        public static string ConvertArgsToLogFile(string str)
        {
            return str.Replace("http://", "").Replace(".", "-").Replace("/", "_").Replace(" ", "").Replace(":", "-") + ".log";
        }

        /// <summary>
        /// Creates a new log file with the date/time stamp appended.
        /// </summary>
        /// <param name="strIdentifier">This is the identifier piece of the log file and usually contains the name of the utility generating the log.</param>
        /// <returns>A streamwriter is returned for us by the calling method.</returns>
        public static System.IO.StreamWriter CreateLogFile(string strIdentifier)
        {
            return new System.IO.StreamWriter(strIdentifier + "_" + DateTime.Now.Year + DateTime.Now.Month.ToString().PadLeft(2, '0')
                + DateTime.Now.Day.ToString().PadLeft(2, '0') + "-" + DateTime.Now.Hour.ToString().PadLeft(2, '0')
                + DateTime.Now.Minute.ToString().PadLeft(2, '0') + DateTime.Now.Second.ToString().PadLeft(2, '0'), true);
        }

        /// <summary>
        /// Hash the command line arguments into a hash table.
        /// </summary>
        /// <param name="strArgs">Command line arguments.</param>
        /// <returns>Hash table containing argument sets.</returns>
        public static Hashtable HashArgs(string[] strArgs)
        {
            System.Collections.Hashtable tbl = new System.Collections.Hashtable();
            for (int i = 0; i < (strArgs.Count() - 1); i += 2)
            {
                tbl.Add(strArgs[i].ToLower(), strArgs[i + 1]);
            }
            return tbl;
        }

        /// <summary>
        /// Create a new document library in the given SPWeb.
        /// </summary>
        /// <param name="LibraryName">Name of the library to use.</param>
        /// <param name="TargetURL">The URL of the SPWeb where the list will be created.</param>
        /// <returns>A reference to the new document library.</returns>
        public static SPList CreateDocumentLibrary(string LibraryName, string TargetURL)
        {
            using (SPSite sps = new SPSite(TargetURL))
            {
                SPWeb spw = sps.OpenWeb();
                SPListTemplateType ltt = SPListTemplateType.DocumentLibrary;
                Guid gID = spw.Lists.Add(LibraryName, null, ltt);
                return spw.Lists[gID];
            }
        }

        public static SPList CreateList(string ListName, string TargetSiteUrl, SPListTemplateType ListType)
        {
            using (SPSite sps = new SPSite(TargetSiteUrl))
            {
                SPWeb spw = sps.OpenWeb();
                Guid gID = spw.Lists.Add(ListName, null, ListType);
                return spw.Lists[gID];
            }
        }

        /// <summary>
        /// Synchronize key library settings from a source library to a target library.
        /// </summary>
        /// <param name="SourceLibrary">The library FROM where settings are copied.</param>
        /// <param name="TargetLibrary">The library TO where settings are copied.</param>
        /// <returns></returns>
        public static bool SyncDocumentLibrarySettings(SPList SourceLibrary, SPList TargetLibrary)
        {
            TargetLibrary.Description = SourceLibrary.Description;
            TargetLibrary.OnQuickLaunch = SourceLibrary.OnQuickLaunch;
            TargetLibrary.EnableVersioning = SourceLibrary.EnableVersioning;
            TargetLibrary.EnableMinorVersions = SourceLibrary.EnableMinorVersions;
            TargetLibrary.MajorVersionLimit = SourceLibrary.MajorVersionLimit;
            TargetLibrary.MajorWithMinorVersionsLimit = SourceLibrary.MajorWithMinorVersionsLimit;
            TargetLibrary.DraftVersionVisibility = SourceLibrary.DraftVersionVisibility;
            TargetLibrary.ForceCheckout = SourceLibrary.ForceCheckout;
            TargetLibrary.ContentTypesEnabled = SourceLibrary.ContentTypesEnabled;
            if (SourceLibrary.ContentTypes.Count > 0)
            {
                List<SPContentType> types = new List<SPContentType>();
                foreach (SPContentType sct in SourceLibrary.ContentTypes)
                {
                    types.Add(sct);
                }
                foreach (SPContentType sct in TargetLibrary.ContentTypes)
                {
                    if (types.Contains(sct))
                    {
                        types.Remove(sct);
                    }
                }
                foreach (SPContentType sct in types)
                {
                    try
                    {
                        TargetLibrary.ContentTypes.Add(sct);
                    }
                    catch (Exception ex)
                    {

                    }
                }
                types.Clear();
            }
            TargetLibrary.DefaultItemOpen = TargetLibrary.DefaultItemOpen;
            TargetLibrary.SendToLocationName = SourceLibrary.SendToLocationName;
            TargetLibrary.SendToLocationUrl = SourceLibrary.SendToLocationUrl;
            TargetLibrary.EnableFolderCreation = SourceLibrary.EnableFolderCreation;
            if (SourceLibrary.WorkflowAssociations.Count > 0)
            {
                List<SPWorkflowAssociation> assoc = new List<SPWorkflowAssociation>();
                foreach (SPWorkflowAssociation swa in SourceLibrary.WorkflowAssociations)
                {
                    assoc.Add(swa);
                }
                foreach (SPWorkflowAssociation swa in TargetLibrary.WorkflowAssociations)
                {
                    if (assoc.Contains(swa))
                    {
                        assoc.Remove(swa);
                    }
                }
                foreach (SPWorkflowAssociation swa in assoc)
                {
                    TargetLibrary.AddWorkflowAssociation(swa);
                }
                assoc.Clear();
            }
            TargetLibrary.Update();
            return true;
        }

        public static bool DuplicateListSettings(SPList SourceList, SPList TargetList)
        {
            SPField fldTarget;
            foreach (SPField fldSource in SourceList.Fields)
            {
                try
                {
                    fldTarget = TargetList.Fields[fldSource.Id];
                }
                catch (Exception ex)
                {
                    List<System.Reflection.PropertyInfo> rpiSource = fldSource.GetType().GetProperties().ToList();
                    string str = TargetList.Fields.Add(fldSource.Title, fldSource.Type, fldSource.Required);
                    foreach (System.Reflection.PropertyInfo rpi in fldSource.GetType().GetProperties())
                    {
                        
                    }
//                    TargetList.Fields.Add(fldTarget);
                }
                //fldTarget.AggregationFunction
                //if (!fld.ReadOnlyField && fld.InternalName != "Attachments" && null != sliSource[fld.InternalName])
                //{
                //    sliTarget[fld.InternalName] = sliSource[fld.InternalName];
                //}
            }
            //TargetLibrary.Description = SourceLibrary.Description;
            //TargetLibrary.OnQuickLaunch = SourceLibrary.OnQuickLaunch;
            //TargetLibrary.EnableVersioning = SourceLibrary.EnableVersioning;
            //TargetLibrary.EnableMinorVersions = SourceLibrary.EnableMinorVersions;
            //TargetLibrary.MajorVersionLimit = SourceLibrary.MajorVersionLimit;
            //TargetLibrary.MajorWithMinorVersionsLimit = SourceLibrary.MajorWithMinorVersionsLimit;
            //TargetLibrary.DraftVersionVisibility = SourceLibrary.DraftVersionVisibility;
            //TargetLibrary.ForceCheckout = SourceLibrary.ForceCheckout;
            //TargetLibrary.ContentTypesEnabled = SourceLibrary.ContentTypesEnabled;
            //if (SourceLibrary.ContentTypes.Count > 0)
            //{
            //    List<SPContentType> types = new List<SPContentType>();
            //    foreach (SPContentType sct in SourceLibrary.ContentTypes)
            //    {
            //        types.Add(sct);
            //    }
            //    foreach (SPContentType sct in TargetLibrary.ContentTypes)
            //    {
            //        if (types.Contains(sct))
            //        {
            //            types.Remove(sct);
            //        }
            //    }
            //    foreach (SPContentType sct in types)
            //    {
            //        try
            //        {
            //            TargetLibrary.ContentTypes.Add(sct);
            //        }
            //        catch (Exception ex)
            //        {

            //        }
            //    }
            //    types.Clear();
            //}
            //TargetLibrary.DefaultItemOpen = TargetLibrary.DefaultItemOpen;
            //TargetLibrary.SendToLocationName = SourceLibrary.SendToLocationName;
            //TargetLibrary.SendToLocationUrl = SourceLibrary.SendToLocationUrl;
            //TargetLibrary.EnableFolderCreation = SourceLibrary.EnableFolderCreation;
            //if (SourceLibrary.WorkflowAssociations.Count > 0)
            //{
            //    List<SPWorkflowAssociation> assoc = new List<SPWorkflowAssociation>();
            //    foreach (SPWorkflowAssociation swa in SourceLibrary.WorkflowAssociations)
            //    {
            //        assoc.Add(swa);
            //    }
            //    foreach (SPWorkflowAssociation swa in TargetLibrary.WorkflowAssociations)
            //    {
            //        if (assoc.Contains(swa))
            //        {
            //            assoc.Remove(swa);
            //        }
            //    }
            //    foreach (SPWorkflowAssociation swa in assoc)
            //    {
            //        TargetLibrary.AddWorkflowAssociation(swa);
            //    }
            //    assoc.Clear();
            //}
            //TargetLibrary.Update();
            return true;
        }

        public static XmlDocument ToXml<T>(List<T> lstTarget)
        {
            XmlDocument xml = new XmlDocument();
            XPathNavigator nav = xml.CreateNavigator();
            using (XmlWriter wtr = nav.AppendChild())
            {
                XmlSerializer szr = new XmlSerializer(typeof(List<T>));
                szr.Serialize(wtr, lstTarget);
            }
            return xml;
        }

        public static List<T> ToList<T>(string xmlFile, List<T> lstTarget)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
            Stream reader = new FileStream(xmlFile, FileMode.Open);
            lstTarget = (List<T>)serializer.Deserialize(reader);
            return lstTarget;
        }

        public static List<T> ToList<T>(Stream xmlStream, List<T> lstTarget)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
            lstTarget = (List<T>)serializer.Deserialize(xmlStream);
            return lstTarget;
        }

        public static List<T> ToList<T>(TextReader xmlStream, List<T> lstTarget)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
            lstTarget = (List<T>)serializer.Deserialize(xmlStream);
            return lstTarget;
        }



        public class SelfSanitizingStreamReader : StreamReader
        {
            private const int EOF = -1;

            public SelfSanitizingStreamReader(Stream stm) : base(stm, true) { }

            public static bool IsLegalChar(int chr)
            {
                return (
                    chr == 0x9 ||
                    chr == 0xA ||
                    chr == 0xD ||
                    (chr >= 0x20 && chr <= 0xD7FF) ||
                    (chr >= 0x0E000 && chr <= 0xFFFD) ||
                    (chr >= 0x10000 && chr <= 0x10FFFF)
                    );
            }

            public override int Read()
            {
                int i;
                do
                {
                    if ((i = base.Read()) == EOF)
                    {
                        break;
                    }
                }
                while
                (!IsLegalChar(i));
                return i;
            }

            public override int Peek()
            {
                int i;
                do
                {
                    i = base.Peek();
                }
                while
                (IsLegalChar(i) && (i = base.Read()) != EOF);
                return i;
            }

            public override int Read(char[] buffer, int index, int count)
            {
                if (buffer == null)
                {
                    throw new ArgumentNullException("buffer");
                }
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException("index");
                }
                if (count < 0)
                {
                    throw new ArgumentOutOfRangeException("count");
                }
                if ((buffer.Length - index) < count)
                {
                    throw new ArgumentException();
                }
                int num = 0;
                do
                {
                    int num2 = this.Read();
                    if (num2 == -1)
                    {
                        return num;
                    }
                    buffer[index + num++] = (char)num2;
                }
                while (num < count);
                return num;
            }

            public override int ReadBlock(char[] buffer, int index, int count)
            {
                int num;
                int num2 = 0;
                do
                {
                    num2 += num = this.Read(buffer, index + num2, count - num2);
                }
                while ((num > 0) && (num2 < count));
                return num2;
            }

            public override string ReadLine()
            {
                StringBuilder builder = new StringBuilder();
                while (true)
                {
                    int num = this.Read();
                    switch (num)
                    {
                        case -1:
                            if (builder.Length > 0)
                            {
                                return builder.ToString();
                            }
                            return null;

                        case 13:
                        case 10:
                            if ((num == 13) && (this.Peek() == 10))
                            {
                                this.Read();
                            }
                            return builder.ToString();
                    }
                    builder.Append((char)num);
                }
            }

            public override string ReadToEnd()
            {
                int num;
                char[] buffer = new char[0x1000];
                StringBuilder builder = new StringBuilder(0x1000);
                while ((num = this.Read(buffer, 0, buffer.Length)) != 0)
                {
                    builder.Append(buffer, 0, num);
                }
                return builder.ToString();
            }
        }

        public class XNodeComparor : IEqualityComparer<System.Xml.Linq.XNode>
        {
            public bool Equals(System.Xml.Linq.XNode source, System.Xml.Linq.XNode target)
            {
                List<string> _sourceAtt = GetListOfAttributesAsString((System.Xml.Linq.XElement)source);
                List<string> _targetAtt = GetListOfAttributesAsString((System.Xml.Linq.XElement)target);
                List<string> _toRemove = new List<string>();
                foreach (string att in _sourceAtt)
                {
                    if (_targetAtt.Contains(att))
                    {
                        _toRemove.Add(att);
                    }
                }
                foreach (string att in _toRemove)
                {
                    _targetAtt.Remove(att);
                    _sourceAtt.Remove(att);
                }
                if ((_sourceAtt.Count() > 0) || (_targetAtt.Count() > 0))
                {
                    return false;
                }
                return true;
            }

            public List<System.Xml.Linq.XNode> GetListOfElements(IEnumerable<System.Xml.Linq.XNode> xml)
            {
                List<System.Xml.Linq.XNode> lst = new List<System.Xml.Linq.XNode>();
                foreach (System.Xml.Linq.XNode nod in xml)
                {
                    if (!(nod is System.Xml.Linq.XComment))
                    {
                        lst.Add(nod);
                    }
                }
                return lst;
            }

            private List<System.Xml.Linq.XAttribute> GetListOfAttributes(System.Xml.Linq.XElement xml)
            {
                List<System.Xml.Linq.XAttribute> lst = new List<System.Xml.Linq.XAttribute>();
                foreach (System.Xml.Linq.XAttribute att in xml.Attributes())
                {
                    lst.Add(att);
                }
                return lst;
            }

            private List<string> GetListOfAttributesAsString(System.Xml.Linq.XElement xml)
            {
                List<string> lst = new List<string>();
                foreach (System.Xml.Linq.XAttribute att in xml.Attributes())
                {
                    lst.Add(att.ToString().ToLower());
                }
                return lst;
            }

            public int GetHashCode(System.Xml.Linq.XNode source)
            {
                return source.GetHashCode();
            }
        }

        public class XElementComparor : IEqualityComparer<System.Xml.Linq.XElement>
        {
            public bool Equals(System.Xml.Linq.XElement source, System.Xml.Linq.XElement target)
            {
                List<string> _sourceAtt = GetListOfAttributesAsString((System.Xml.Linq.XElement)source);
                List<string> _targetAtt = GetListOfAttributesAsString((System.Xml.Linq.XElement)target);
                List<string> _toRemove = new List<string>();
                foreach (string att in _sourceAtt)
                {
                    if (_targetAtt.Contains(att))
                    {
                        _toRemove.Add(att);
                    }
                }
                foreach (string att in _toRemove)
                {
                    _targetAtt.Remove(att);
                    _sourceAtt.Remove(att);
                }
                if ((_sourceAtt.Count() > 0) || (_targetAtt.Count() > 0))
                {
                    return false;
                }
                return true;
            }

            public List<System.Xml.Linq.XElement> GetListOfElements(IEnumerable<System.Xml.Linq.XElement> xml)
            {
                List<System.Xml.Linq.XElement> lst = new List<System.Xml.Linq.XElement>();
                foreach (System.Xml.Linq.XNode nod in xml)
                {
                    if (!(nod is System.Xml.Linq.XComment))
                    {
                        lst.Add((XElement)nod);
                    }
                }
                return lst;
            }

            private List<System.Xml.Linq.XAttribute> GetListOfAttributes(System.Xml.Linq.XElement xml)
            {
                List<System.Xml.Linq.XAttribute> lst = new List<System.Xml.Linq.XAttribute>();
                foreach (System.Xml.Linq.XAttribute att in xml.Attributes())
                {
                    lst.Add(att);
                }
                return lst;
            }

            private List<string> GetListOfAttributesAsString(System.Xml.Linq.XElement xml)
            {
                List<string> lst = new List<string>();
                foreach (System.Xml.Linq.XAttribute att in xml.Attributes())
                {
                    lst.Add(att.ToString().ToLower());
                }
                return lst;
            }

            public int GetHashCode(System.Xml.Linq.XElement source)
            {
                return source.GetHashCode();
            }
        }
    }
}
